#include <iostream>
#include <sstream> //ostringstream: 字符串流操作
#include <functional> //std::function, std::placeholders
#include <algorithm> //for_each
#include <vector>

using std::cout;
using std::endl;
using namespace std::placeholders; //_1,_2...
using std::ref; //给bind传递引用参数
using ostream = std::ostream;
using ostringstream = std::ostringstream;
template <typename T>
using vector = std::vector<T>;
using string = std::string;


int add(int a, int b) {
    return a+b;
}

struct FuncObj{
    FuncObj() {}
    int operator()(int a, int b) {
        return a+b;
    }  
};

struct C {
    virtual int add(int a, int b) {
        cout << "calling C::add(int,int)..." << endl;
        return a+b;
    }
};

struct D : C {
    int add(int a, int b) override {
        cout << "calling D::add(int,int)..." << endl;
        return a+b;
    }
};


ostream & print(ostream &os, const string& s, char c) {
    os << s << c;
    return os;
}


int main() {
    vector<string> words{"Hello", "world", "this", "is", "C++11"};
    ostringstream os;
    // ostream不能拷贝，若希望传递给bind一个对象，
    // 而不拷贝它，就必须使用标准库提供的ref函数
    for_each(words.begin(), words.end(),
                   bind(print, ref(os), _1, ' '));
    cout << os.str() << endl;

    std::function<int(int, int)> callee1;
    callee1 = add; cout << callee1(0,1) << endl;
    callee1 = FuncObj(); cout << callee1(1,2) << endl;
    auto objc = C();
    std::function<int(C, int, int)> callee2;
    callee2 = &C::add; cout << callee2(objc,2,3) << endl;
    std::function<int(C*, int, int)> callee3;
    callee3 = &C::add; cout << callee3(&objc, 3,4) << endl;
    std::function<int(C&, int, int)> callee4;
    D objd;
    C &cr = objd;
    callee4 = &C::add; cout << callee4(cr, 4,5) << endl;

    auto callee5 = std::bind(add, 10, _1);
    cout << callee5(1) << endl;
    auto callee6 = std::bind(FuncObj(), _1, 11);
    cout << callee6(2) << endl;
    auto callee7 = std::bind(&C::add, _1, _2, _3);
    callee7(objc, 3, 12);
    callee7(&objc, 4, 13);
    callee7(cr, 5, 14);

    return 0;
}
